package cz.data.domain.driver.mongodb.service;

import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoIterable;
import cz.data.common.base.BaseResponse;
import cz.data.common.mongo.CacheMongoClientBean;
import cz.data.common.support.db.DbProperty;
import cz.data.common.support.db.DbType;
import cz.data.common.support.db.core.DbColumn;
import cz.data.common.support.db.core.DbTable;
import cz.data.common.support.db.driver.TableOperation;
import cz.data.common.support.db.manage.DbManage;
import cz.data.common.support.db.manage.DbManageFactory;
import cz.data.common.support.db.manage.DbManageRegistry;
import cz.data.common.utils.ThrowableUtil;
import cz.data.domain.metadata.model.MetadataUtil;
import cz.data.domain.metadata.model.entity.MetadataSourceEntity;
import cz.data.domain.metadata.rpc.MetadataFeign;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;

@Component
public class MongoMetadataService {
    @Resource
    MetadataFeign metadataFeign;

    public BaseResponse connect(DbProperty property) {
        MongoClient mongoClient = null;
        try {
            String mongodbUrl = DbType.MONGODB.getUrl();
            mongodbUrl = mongodbUrl.replace("${host}", property.getHost())
                    .replace("${port}", String.valueOf(property.getPort()))
                    .replace("${user}", property.getUsername())
                    .replace("${pass}", property.getPassword());
            property.setId(null);
            property.setMaxConn(1);
            mongoClient = CacheMongoClientBean.create(mongodbUrl, property);
            MongoIterable<String> databaseNames = mongoClient.listDatabaseNames();
            databaseNames.first();
            return BaseResponse.success();
        } catch (Exception e) {
            return BaseResponse.error(500, e.getMessage());
        } finally {
            if (Objects.nonNull(mongoClient)) {
                mongoClient.close();
            }
        }
    }

    public boolean createTable(TableOperation operation) {
        MetadataSourceEntity source = metadataFeign.getMetadataSourceById(operation.getSourceId());
        DbProperty property = MetadataUtil.dbProperty(source);
        DbManage dbManage = null;
        try {
            DbTable table = operation.getTable();
            table.setDbName(property.getDbName());
            table.setSchemaName(property.getSchemaName());
            DbManageFactory factory = DbManageRegistry.factory(property.getDbTypeEnum());
            dbManage = factory.factory(property);
            return dbManage.createTable(operation.getTable(), operation.getProperties());
        } finally {
            if (Objects.nonNull(dbManage)) {
                ThrowableUtil.throwable(dbManage::close);
            }
        }
    }

    public boolean dropTable(TableOperation operation) {
        MetadataSourceEntity source = metadataFeign.getMetadataSourceById(operation.getSourceId());
        DbProperty property = MetadataUtil.dbProperty(source);
        DbManage dbManage = null;
        try {
            DbTable table = operation.getTable();
            table.setDbName(property.getDbName());
            table.setSchemaName(property.getSchemaName());
            DbManageFactory factory = DbManageRegistry.factory(property.getDbTypeEnum());
            dbManage = factory.factory(property);
            return dbManage.deleteTable(table);
        } finally {
            if (Objects.nonNull(dbManage)) {
                ThrowableUtil.throwable(dbManage::close);
            }
        }
    }

    public List<DbTable> getSourceAllTable(String sourceId) {
        return getSourceAllTable(metadataFeign.getMetadataSourceById(sourceId));
    }

    public List<DbTable> getSourceAllTable(MetadataSourceEntity source) {
        DbProperty property = MetadataUtil.dbProperty(source);
        DbManage dbManage = null;
        try {
            DbManageFactory factory = DbManageRegistry.factory(property.getDbTypeEnum());
            dbManage = factory.factory(property);
            return dbManage.getTables(property.getDbName(), property.getSchemaName());
        } finally {
            if (Objects.nonNull(dbManage)) {
                ThrowableUtil.throwable(dbManage::close);
            }
        }
    }

    public List<DbColumn> getSourceTableColumns(String sourceId, String tableName) {
        MetadataSourceEntity source = metadataFeign.getMetadataSourceById(sourceId);
        return getSourceTableColumns(source, tableName);
    }

    public List<DbColumn> getSourceTableColumns(MetadataSourceEntity source, String tableName) {
        DbProperty property = MetadataUtil.dbProperty(source);
        DbManage dbManage = null;
        try {
            DbManageFactory factory = DbManageRegistry.factory(property.getDbTypeEnum());
            dbManage = factory.factory(property);
            return dbManage.getTableColumns(property.getDbName(), property.getSchemaName(), tableName);
        } finally {
            if (Objects.nonNull(dbManage)) {
                ThrowableUtil.throwable(dbManage::close);
            }
        }
    }
}
